

namespace Stee.CAP8.MessageBus.Sagas.Order.Sagas
{
    using Stee.CAP8.MessageBus.Interface.Models;
    using Stee.CAP8.MessageBus.Sagas.Core.Attributes;
    using Stee.CAP8.MessageBus.Sagas.Core.Bus;
    using Stee.CAP8.MessageBus.Sagas.Core.Common;
    using Stee.CAP8.MessageBus.Sagas.Core.Handlers;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas;
    using Stee.CAP8.MessageBus.Sagas.Core.Storages.Nodes;
    using Stee.CAP8.MessageBus.Sagas.Core.Storages.Steps;
    using Stee.CAP8.MessageBus.Sagas.Messages.RedundantSettings;
    using Stee.CAP8.MessageBus.Sagas.Order.Sagas.Data;
    using Stee.CAP8.MessageBus.Sagas.Payment.Dtos;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Threading.Tasks;

    [SagaTopic("order_application")]
    public class OrderSagaMain : BaseMainSaga<OrderSagaData>, IHandleMessages<PaymentInfo>
    {
        private readonly string clientId = Guid.NewGuid().ToString();
        private readonly string recordID = Guid.NewGuid().ToString();
        private readonly string token = Guid.NewGuid().ToString();
        private readonly ConcurrentDictionary<string, OrderInfo> orderlist = new ConcurrentDictionary<string, OrderInfo>();

        private const string PaymentAction = "PaymentSub.Payment";
        private const string StockAction = "StockSub.StockAdjust";

        public OrderSagaMain() { }

        public OrderSagaMain(IBus bus, ISagaStepStorage sagaStepStorage, ISagaNodeStorage sagaNodeStorage) :
            base(bus, sagaStepStorage, sagaNodeStorage)
        {
            this.DeadlineSeconds = 8;//设置超时间为4秒 读取设置或者配置
        }
        /// <summary>
        /// saga启动
        /// </summary>
        /// <param name="orderInfo"></param>
        /// <returns></returns>
        public async Task<string> StartSaga(OrderInfo orderInfo)
        {

            //初始化message和sagaData
            var message = new CommandMessage()//call saga
            {
                CorrelationID = orderInfo.OrderId.ToString(),
                ClientID = clientId,
                JWT = token,
                CreateDT = DateTime.Now,
            };
            var saga = new OrderSagaData(message.CorrelationID);

            this.SetParams(message,saga);

            await this.CreateOrder(orderInfo).ConfigureAwait(false);

            return await this.WaitSagaFinish().ConfigureAwait(false);
        }

       

        /// <summary>
        /// 创建订单
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task CreateOrder(OrderInfo orderInfo)
        {


            await Task.Run(() =>
            {
                Console.WriteLine("收到商品信息");
                //写数据库
                if (orderInfo != null)
                {
                    this.SaveOrder(orderInfo);
                }
                this.Data.OrderCreated = true;
                var paymentInfo = new PaymentInfo
                {
                    Amount = orderInfo.Balance,
                    PaymentMethod = "支付宝支付",
                    ThridPartPayNumber = "11212123123"
                };
                //paymentInfo=> {classfuname:"",object:json}<T>
                //支付操作
                this.SendCommand(actionName: SagaClassHelper.PaymentAction,
                            topicName: "payment_application",
                            replyChannel: "order_application",
                            instance: paymentInfo);
                var stockInfos = new List<StockInfo> { new StockInfo { Count = 2, ProductSkuNumber = "PE1456789" } };

                ////库存调整
                //this.SendCommand(actionName: SagaClassHelper.StockAdjustAction,
                //            topicName: "stock_application",
                //            replyChannel: "order_application",
                //            instance: stockInfos);
            }).ConfigureAwait(false);

        }


        /// <summary>
        /// 子事务支付完成
        /// 记录支付信息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        [SagaAction(PaymentAction)]
        public async Task HandlePayemented(CommandMessage message) 
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            //var paemntinfo = message.Data.ToObject<>

            Console.WriteLine("支付完成记录");
            SetChangedAction(Data.OrderCreated, true);
            this.Data.OrderPaymented = true;

            await this.Post().ConfigureAwait(false);
        }
        /// <summary>
        /// 子事务库存调整完成
        /// 记录库存信息
        /// </summary>
        /// <returns></returns>
        [SagaAction(StockAction)]
        public async Task HandleAdjustStocked(CommandMessage message)
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            Console.WriteLine("调整库存成功");
            this.Data.OrderStockAdjusted = true;
            await this.Post().ConfigureAwait(false);
        }
        #region 业务方法
        /// <summary>
        /// 创建订单方法（数据库操作）
        /// </summary>
        /// <param name="orderInfo"></param>
        /// <returns></returns>
        private OrderInfo SaveOrder(OrderInfo orderInfo) =>
            this.orderlist.AddOrUpdate(orderInfo.OrderId.ToString(), orderInfo, (key, value) => value);
        /// <summary>
        /// 取消订单方法（数据库操作）
        /// </summary>
        /// <param name="orderInfo"></param>
        /// <returns></returns>
        private bool CancelSaveOrder(OrderInfo orderInfo) => this.orderlist.TryRemove(orderInfo.OrderId.ToString(), out orderInfo);
        private async Task Post()
        {
            if (this.Data.IsDone())
            {
                Console.WriteLine("事务执行完毕");
            }

        }

        public Task Handle(PaymentInfo sagaStepData)
        {
            Console.WriteLine("调用sagaStepData");
            return Task.CompletedTask;
        }

     
        #endregion
    }
}
